package com.zenithmind.mall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.common.context.UserContext;
import com.zenithmind.common.exception.BusinessException;
import com.zenithmind.common.result.PageResult;
import com.zenithmind.mall.mapper.CouponMapper;
import com.zenithmind.mall.mapper.UserCouponMapper;
import com.zenithmind.mall.pojo.dto.CouponDTO;
import com.zenithmind.mall.pojo.entity.Coupon;
import com.zenithmind.mall.pojo.entity.UserCoupon;
import com.zenithmind.mall.pojo.query.CouponQuery;
import com.zenithmind.mall.pojo.vo.CouponVO;
import com.zenithmind.mall.service.CouponService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 优惠券服务实现
 * 
 * @author ZenithMind Team
 * @since 2025-06-09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements CouponService {

    private final UserCouponMapper userCouponMapper;

    @Override
    public PageResult<CouponVO> getCouponPage(CouponQuery query) {
        Page<Coupon> page = new Page<>(query.getCurrent(), query.getSize());

        LambdaQueryWrapper<Coupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Coupon::getIsDeleted, 0)
               .like(StringUtils.hasText(query.getName()), Coupon::getName, query.getName())
               .eq(query.getType() != null, Coupon::getType, query.getType())
               .eq(query.getStatus() != null, Coupon::getStatus, query.getStatus())
               .ge(query.getStartTime() != null, Coupon::getStartTime, query.getStartTime())
               .le(query.getEndTime() != null, Coupon::getEndTime, query.getEndTime())
               .orderByDesc(Coupon::getCreateTime);

        Page<Coupon> result = page(page, wrapper);

        List<CouponVO> voList = result.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());

        return new PageResult<>(voList, result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public CouponVO getCouponById(String id) {
        Coupon coupon = getById(id);
        if (coupon == null) {
            throw new BusinessException("优惠券不存在");
        }
        return convertToVO(coupon);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createCoupon(CouponDTO couponDTO) {
        // 验证优惠券数据
        validateCouponData(couponDTO);
        
        Coupon coupon = new Coupon();
        BeanUtils.copyProperties(couponDTO, coupon);
        
        // 设置默认值
        if (coupon.getStatus() == null) {
            coupon.setStatus(1); // 默认启用
        }
        if (coupon.getReceivedCount() == null) {
            coupon.setReceivedCount(0);
        }
        if (coupon.getUsedCount() == null) {
            coupon.setUsedCount(0);
        }
        
        coupon.setCreateBy(UserContext.getUserId());
        
        if (!save(coupon)) {
            throw new BusinessException("创建优惠券失败");
        }
        
        log.info("创建优惠券成功: {}", coupon.getId());
        return coupon.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCoupon(String id, CouponDTO couponDTO) {
        Coupon existCoupon = getById(id);
        if (existCoupon == null) {
            throw new BusinessException("优惠券不存在");
        }
        
        // 验证优惠券数据
        validateCouponData(couponDTO);
        
        Coupon coupon = new Coupon();
        BeanUtils.copyProperties(couponDTO, coupon);
        coupon.setId(id);
        coupon.setUpdateBy(UserContext.getUserId());
        
        boolean result = updateById(coupon);
        if (result) {
            log.info("更新优惠券成功: {}", id);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteCoupon(String id) {
        Coupon coupon = getById(id);
        if (coupon == null) {
            throw new BusinessException("优惠券不存在");
        }
        
        // 检查是否有用户已领取
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getCouponId, id)
               .eq(UserCoupon::getIsDeleted, 0);
        
        if (userCouponMapper.selectCount(wrapper) > 0) {
            throw new BusinessException("该优惠券已被用户领取，无法删除");
        }
        
        boolean result = removeById(id);
        if (result) {
            log.info("删除优惠券成功: {}", id);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteCouponsBatch(List<String> ids) {
        if (ids == null || ids.isEmpty()) {
            return true;
        }
        
        for (String id : ids) {
            deleteCoupon(id);
        }
        return true;
    }

    @Override
    public List<CouponVO> getAvailableCoupons(String userId, BigDecimal orderAmount) {
        // 查询用户可用的优惠券
        LambdaQueryWrapper<UserCoupon> userCouponWrapper = new LambdaQueryWrapper<>();
        userCouponWrapper.eq(UserCoupon::getUserId, userId)
                        .eq(UserCoupon::getStatus, 0) // 未使用
                        .eq(UserCoupon::getIsDeleted, 0);
        
        List<UserCoupon> userCoupons = userCouponMapper.selectList(userCouponWrapper);
        
        return userCoupons.stream()
                .map(userCoupon -> {
                    Coupon coupon = getById(userCoupon.getCouponId());
                    if (coupon != null && isCouponAvailable(coupon, orderAmount)) {
                        CouponVO vo = convertToVO(coupon);
                        vo.setUserCouponId(userCoupon.getId());
                        return vo;
                    }
                    return null;
                })
                .filter(vo -> vo != null)
                .collect(Collectors.toList());
    }

    @Override
    public List<CouponVO> getUserCoupons(String userId, Integer status) {
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getUserId, userId)
               .eq(UserCoupon::getIsDeleted, 0)
               .eq(status != null, UserCoupon::getStatus, status)
               .orderByDesc(UserCoupon::getCreateTime);
        
        List<UserCoupon> userCoupons = userCouponMapper.selectList(wrapper);
        
        return userCoupons.stream()
                .map(userCoupon -> {
                    Coupon coupon = getById(userCoupon.getCouponId());
                    if (coupon != null) {
                        CouponVO vo = convertToVO(coupon);
                        vo.setUserCouponId(userCoupon.getId());
                        vo.setUserCouponStatus(userCoupon.getStatus());
                        vo.setReceiveTime(userCoupon.getCreateTime());
                        vo.setUseTime(userCoupon.getUseTime());
                        return vo;
                    }
                    return null;
                })
                .filter(vo -> vo != null)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean receiveCoupon(String couponId, String userId) {
        Coupon coupon = getById(couponId);
        if (coupon == null) {
            throw new BusinessException("优惠券不存在");
        }
        
        // 检查优惠券状态
        if (coupon.getStatus() != 1) {
            throw new BusinessException("优惠券已停用");
        }
        
        // 检查时间范围
        LocalDateTime now = LocalDateTime.now();
        if (now.isBefore(coupon.getStartTime()) || now.isAfter(coupon.getEndTime())) {
            throw new BusinessException("优惠券不在有效期内");
        }
        
        // 检查库存
        if (coupon.getTotalCount() != null && coupon.getReceivedCount() >= coupon.getTotalCount()) {
            throw new BusinessException("优惠券已被抢完");
        }
        
        // 检查用户是否已领取
        LambdaQueryWrapper<UserCoupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserCoupon::getUserId, userId)
               .eq(UserCoupon::getCouponId, couponId)
               .eq(UserCoupon::getIsDeleted, 0);
        
        if (userCouponMapper.selectCount(wrapper) > 0) {
            throw new BusinessException("您已领取过该优惠券");
        }
        
        // 创建用户优惠券记录
        UserCoupon userCoupon = new UserCoupon();
        userCoupon.setUserId(userId);
        userCoupon.setCouponId(couponId);
        userCoupon.setStatus(0); // 未使用
        userCoupon.setCreateBy(userId);
        
        if (userCouponMapper.insert(userCoupon) <= 0) {
            throw new BusinessException("领取优惠券失败");
        }
        
        // 更新优惠券领取数量
        LambdaUpdateWrapper<Coupon> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Coupon::getId, couponId)
                    .setSql("received_count = received_count + 1");
        update(updateWrapper);
        
        log.info("用户 {} 领取优惠券成功: {}", userId, couponId);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean useCoupon(String userCouponId, String orderId) {
        UserCoupon userCoupon = userCouponMapper.selectById(userCouponId);
        if (userCoupon == null) {
            throw new BusinessException("用户优惠券不存在");
        }
        
        if (userCoupon.getStatus() != 0) {
            throw new BusinessException("优惠券已使用或已过期");
        }
        
        // 更新用户优惠券状态
        userCoupon.setStatus(1); // 已使用
        userCoupon.setOrderId(orderId);
        userCoupon.setUseTime(LocalDateTime.now());
        userCoupon.setUpdateBy(userCoupon.getUserId());
        
        if (userCouponMapper.updateById(userCoupon) <= 0) {
            throw new BusinessException("使用优惠券失败");
        }
        
        // 更新优惠券使用数量
        LambdaUpdateWrapper<Coupon> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Coupon::getId, userCoupon.getCouponId())
                    .setSql("used_count = used_count + 1");
        update(updateWrapper);
        
        log.info("使用优惠券成功: {}", userCouponId);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean returnCoupon(String userCouponId) {
        UserCoupon userCoupon = userCouponMapper.selectById(userCouponId);
        if (userCoupon == null) {
            throw new BusinessException("用户优惠券不存在");
        }
        
        if (userCoupon.getStatus() != 1) {
            throw new BusinessException("优惠券未使用，无需退还");
        }
        
        // 更新用户优惠券状态
        userCoupon.setStatus(0); // 未使用
        userCoupon.setOrderId(null);
        userCoupon.setUseTime(null);
        userCoupon.setUpdateBy(userCoupon.getUserId());
        
        if (userCouponMapper.updateById(userCoupon) <= 0) {
            throw new BusinessException("退还优惠券失败");
        }
        
        // 更新优惠券使用数量
        LambdaUpdateWrapper<Coupon> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Coupon::getId, userCoupon.getCouponId())
                    .setSql("used_count = used_count - 1");
        update(updateWrapper);
        
        log.info("退还优惠券成功: {}", userCouponId);
        return true;
    }

    @Override
    public Boolean checkCouponAvailable(String userCouponId, BigDecimal orderAmount) {
        UserCoupon userCoupon = userCouponMapper.selectById(userCouponId);
        if (userCoupon == null || userCoupon.getStatus() != 0) {
            return false;
        }
        
        Coupon coupon = getById(userCoupon.getCouponId());
        return coupon != null && isCouponAvailable(coupon, orderAmount);
    }

    @Override
    public BigDecimal calculateDiscountAmount(String userCouponId, BigDecimal orderAmount) {
        UserCoupon userCoupon = userCouponMapper.selectById(userCouponId);
        if (userCoupon == null || userCoupon.getStatus() != 0) {
            return BigDecimal.ZERO;
        }
        
        Coupon coupon = getById(userCoupon.getCouponId());
        if (coupon == null || !isCouponAvailable(coupon, orderAmount)) {
            return BigDecimal.ZERO;
        }
        
        BigDecimal discountAmount = BigDecimal.ZERO;
        
        switch (coupon.getType()) {
            case 1: // 满减券
                discountAmount = coupon.getAmount();
                break;
            case 2: // 折扣券
                discountAmount = orderAmount.multiply(BigDecimal.ONE.subtract(coupon.getDiscountRate().divide(BigDecimal.valueOf(100))));
                break;
            case 3: // 免邮券
                // 免邮券的优惠金额需要根据实际邮费计算
                discountAmount = BigDecimal.ZERO;
                break;
        }
        
        // 确保优惠金额不超过订单金额
        return discountAmount.min(orderAmount);
    }

    @Override
    public List<CouponVO> getHotCoupons(Integer limit) {
        if (limit == null || limit <= 0) {
            limit = 10;
        }
        
        LambdaQueryWrapper<Coupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Coupon::getIsDeleted, 0)
               .eq(Coupon::getStatus, 1)
               .le(Coupon::getStartTime, LocalDateTime.now())
               .ge(Coupon::getEndTime, LocalDateTime.now())
               .orderByDesc(Coupon::getReceivedCount)
               .last("LIMIT " + limit);
        
        List<Coupon> coupons = list(wrapper);
        return coupons.stream().map(this::convertToVO).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateCouponStatus(String id, Integer status) {
        Coupon coupon = getById(id);
        if (coupon == null) {
            throw new BusinessException("优惠券不存在");
        }
        
        LambdaUpdateWrapper<Coupon> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Coupon::getId, id)
               .set(Coupon::getStatus, status)
               .set(Coupon::getUpdateBy, UserContext.getUserId())
               .set(Coupon::getUpdateTime, LocalDateTime.now());
        
        boolean result = update(wrapper);
        if (result) {
            log.info("更新优惠券状态成功: {} -> {}", id, status);
        }
        return result;
    }

    /**
     * 验证优惠券数据
     */
    private void validateCouponData(CouponDTO couponDTO) {
        if (couponDTO.getStartTime() != null && couponDTO.getEndTime() != null) {
            if (couponDTO.getStartTime().isAfter(couponDTO.getEndTime())) {
                throw new BusinessException("开始时间不能晚于结束时间");
            }
        }
        
        if (couponDTO.getType() == 1 && couponDTO.getDiscountAmount() == null) {
            throw new BusinessException("满减券必须设置优惠金额");
        }
        
        if (couponDTO.getType() == 2 && couponDTO.getDiscountRate() == null) {
            throw new BusinessException("折扣券必须设置折扣率");
        }
    }

    /**
     * 检查优惠券是否可用
     */
    private boolean isCouponAvailable(Coupon coupon, BigDecimal orderAmount) {
        LocalDateTime now = LocalDateTime.now();
        
        // 检查状态
        if (coupon.getStatus() != 1) {
            return false;
        }
        
        // 检查时间
        if (now.isBefore(coupon.getStartTime()) || now.isAfter(coupon.getEndTime())) {
            return false;
        }
        
        // 检查最低消费金额
        if (coupon.getMinAmount() != null && orderAmount.compareTo(coupon.getMinAmount()) < 0) {
            return false;
        }
        
        return true;
    }

    /**
     * 转换为VO
     */
    private CouponVO convertToVO(Coupon coupon) {
        CouponVO vo = new CouponVO();
        BeanUtils.copyProperties(coupon, vo);
        
        // 设置类型文本
        switch (coupon.getType()) {
            case 1:
                vo.setTypeText("满减券");
                break;
            case 2:
                vo.setTypeText("折扣券");
                break;
            case 3:
                vo.setTypeText("免邮券");
                break;
            default:
                vo.setTypeText("未知");
        }
        
        // 设置状态文本
        vo.setStatusText(coupon.getStatus() == 1 ? "启用" : "禁用");
        
        // 计算剩余数量
        if (coupon.getTotalCount() != null) {
            vo.setRemainingCount(coupon.getTotalCount() - coupon.getReceivedCount());
        }
        
        return vo;
    }
}
